package com.fuyao.cloud.personnel.library.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyao.cloud.common.biz.dto.PageQuery;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.constant.SecurityConstants;
import com.fuyao.cloud.common.core.flowable.enums.ProcessStatusEnum;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.excel.annotation.ResponseExcel;
import com.fuyao.cloud.common.log.annotation.SysLog;
import com.fuyao.cloud.common.security.component.PermissionService;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import com.fuyao.cloud.flowable.feign.RemoteFlowableService;
import com.fuyao.cloud.personnel.library.dto.FlowCallBackDto;
import com.fuyao.cloud.personnel.library.entity.ApplyBook;
import com.fuyao.cloud.personnel.library.entity.Book;
import com.fuyao.cloud.personnel.library.entity.BookApply;
import com.fuyao.cloud.personnel.library.service.ApplyBookService;
import com.fuyao.cloud.personnel.library.service.BookApplyService;
import com.fuyao.cloud.personnel.library.service.BookService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
@RequiredArgsConstructor
@RequestMapping("/bookApply")
@Api(value = "bookApply", tags = "借书申请")
public class BookApplyController {

    private final BookService bookService;
    private final BookApplyService bookApplyService;
    private final ApplyBookService applyBookService;
    private final RemoteFlowableService remoteFlowableService;
    private final PermissionService pms;


    /**
     * 分页查询
     *
     * @param pageQuery 分页对象
     */
    @ApiOperation(value = "分页查询", notes = "分页查询")
    @PostMapping("/page")
    public R<Page<BookApply>> getPage(PageQuery<BookApply> pageQuery) {
        if (!pms.hasPermission("book-admin")) {
            pageQuery.getExample().setBorrowerId(SecurityUtils.getUser().getId());
        }
        return R.ok(bookApplyService.getPage(pageQuery));
    }


    /**
     * 通过id查询
     *
     * @param id id
     * @return R
     */
    @ApiOperation(value = "通过id查询", notes = "通过id查询")
    @GetMapping("/{id}")
    public R<BookApply> getById(@PathVariable("id") Long id) {
        BookApply bookApply = bookApplyService.getById(id);
        List<ApplyBook> applyBooks = applyBookService.listBooks(bookApply.getId());
        bookApply.setBooks(applyBooks);
        return R.ok(bookApply);
    }

    /**
     * 新增
     *
     * @return R
     */
    @ApiOperation(value = "新增", notes = "新增")
    @SysLog("新增")
    @PostMapping
    public R<BookApply> save(@RequestBody BookApply bookApply) {
        bookApplyService.save(bookApply);

        BookApply finalBookApply = bookApply;
        bookApply.getBooks().forEach(applyBook -> applyBook.setBookApplyId(finalBookApply.getId()));
        List<ApplyBook> newBooks = new ArrayList<>(bookApply.getBooks());
        applyBookService.saveBatch(newBooks);

        bookApply = bookApplyService.getById(bookApply.getId());
        List<ApplyBook> applyBooks1 = applyBookService.listBooks(bookApply.getId());
        bookApply.setBooks(applyBooks1);

        return R.ok(bookApply);
    }

    /**
     * 修改
     *
     * @return R
     */
    @ApiOperation(value = "修改", notes = "修改")
    @SysLog("修改")
    @PutMapping
    public R<BookApply> updateById(@RequestBody BookApply bookApply) {

        List<ApplyBook> applyBooks = applyBookService.list(Wrappers.<ApplyBook>lambdaQuery().eq(ApplyBook::getBookApplyId, bookApply.getId()));

        List<ApplyBook> newBooks = bookApply.getBooks().stream().filter(applyBook -> applyBook.getId() == null || applyBook.getId() == -1).collect(Collectors.toList());

        List<ApplyBook> oldBooks = bookApply.getBooks().stream().filter(applyBook -> applyBook.getId() != null && applyBook.getId() != -1).collect(Collectors.toList());
        Set<Long> bookIds = oldBooks.stream().map(ApplyBook::getBookId).collect(Collectors.toSet());

        List<ApplyBook> removedBooks = applyBooks.stream().filter(applyBook -> !bookIds.contains(applyBook.getBookId())).collect(Collectors.toList());


        bookApplyService.updateById(bookApply);


        applyBookService.removeBatchByIds(removedBooks);
        newBooks.forEach(applyBook -> {
            applyBook.setBookApplyId(bookApply.getId());
            applyBook.setUnid(IdUtil.simpleUUID());
        });
        applyBookService.saveBatch(newBooks);
        applyBookService.updateBatchById(oldBooks);

        List<ApplyBook> applyBooks1 = applyBookService.listBooks(bookApply.getId());
        bookApply.setBooks(applyBooks1);

        return R.ok(bookApply);
    }

    /**
     * 通过id删除
     *
     * @param id id
     * @return R
     */
    @ApiOperation(value = "通过id删除", notes = "通过id删除")
    @SysLog("通过id删除")
    @DeleteMapping("/{id}")
    public R<Boolean> removeById(@PathVariable Long id) {
        applyBookService.remove(Wrappers.<ApplyBook>lambdaQuery().eq(ApplyBook::getBookApplyId, id));
        return R.ok(bookApplyService.removeById(id));
    }


    /**
     * 导出excel 表格
     *
     * @param bookApply 查询条件
     * @return excel 文件流
     */
    @ResponseExcel
    @GetMapping("/export")
    public List<BookApply> export(BookApply bookApply) {
        return bookApplyService.list(Wrappers.query(bookApply));
    }

    /**
     * 创建方法
     */
    @GetMapping(value = "/create")
    public R<BookApply> create() {
        return R.ok(bookApplyService.create());
    }

    /**
     * 批量删除方法
     *
     * @return R
     */
    @ApiOperation(value = "批量删除", notes = "批量删除")
    @SysLog("批量删除")
    @DeleteMapping("/batchDelete")
    public R<Boolean> batchDelete(@RequestBody List<Long> ids) {
        bookApplyService.removeByIds(ids);
        applyBookService.remove(Wrappers.<ApplyBook>lambdaQuery().in(ApplyBook::getBookApplyId, ids));
        ids.forEach(id -> remoteFlowableService.deleteByBusinessKey("bookApply:" + id, SecurityConstants.FROM_IN));
        return R.ok(Boolean.TRUE);
    }

    /**
     * 创建方法
     */
    @PostMapping(value = "/borrowHistory/{bookId}")
    public R<IPage<BookApply>> borrowHistory(@RequestBody PageQuery<BookApply> pageQuery, @PathVariable Long bookId) {
        return R.ok(bookApplyService.borrowHistory(pageQuery.getPage(), bookId));
    }


    @ApiOperation(value = "归还书籍", notes = "归还书籍")
    @PostMapping("/returnBook")
    public R<Boolean> returnBook(@RequestBody List<Long> ids) {
        List<ApplyBook> applyBooks = applyBookService.listByIds(ids);
        applyBooks.forEach(applyBook -> {
            applyBook.setStatus(3);
            applyBook.setReturnDateTime(LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DatePattern.NORM_DATETIME_PATTERN));
        });
        applyBookService.updateBatchById(applyBooks);

        List<Book> books = bookService.listByIds(applyBooks.stream().map(ApplyBook::getBookId).collect(Collectors.toSet()));
        books.forEach(book -> book.setStatus(0));
        bookService.updateBatchById(books);

        return R.ok(Boolean.TRUE);
    }

    @ApiOperation(value = "归还书籍", notes = "归还书籍")
    @PostMapping("/checkBooksStatus")
    public R<List<Book>> checkBooksStatus(@RequestBody List<Long> ids) {
        List<Book> books = bookService.listByIds(ids);

        List<Book> errorStatusBooks = books.stream().filter(book -> book.getStatus() != 0).collect(Collectors.toList());
        if (errorStatusBooks.isEmpty()) {
            return R.ok(Collections.emptyList());
        }
        return R.failed(errorStatusBooks);
    }

    @ApiOperation(value = "起草环节结束回调方法", notes = "起草环节结束回调方法")
    @PostMapping(value = "/flowStart", produces = "application/json")
    public R<Integer> draftEndCallback(@RequestBody FlowCallBackDto params) {
        if (params != null && StrUtil.isNotBlank(params.getBusinessKey())) {
            BookApply bookApply = bookApplyService.getById(params.getBusinessKey().split(":")[1]);
            bookApply.setStatus(1);
            bookApplyService.updateById(bookApply);
            List<ApplyBook> applyBooks = applyBookService.findBooksByApplyId(bookApply.getId());
            applyBooks.forEach(applyBook -> {
                applyBook.setBorrowDateTime(null);
                applyBook.setStatus(1);
            });
            applyBookService.updateBatchById(applyBooks);
            return R.ok(CommonConstants.SUCCESS, "修改状态成功");
        }
        return R.ok(CommonConstants.FAIL, "起草环节结束回调方法");
    }

    @ApiOperation(value = "回退至起草环节回调方法", notes = "回退至起草环节回调方法")
    @PostMapping(value = "/flowDraft", produces = "application/json")
    public R<Integer> returnCallback(@RequestBody FlowCallBackDto params) {
        if (params != null && StrUtil.isNotBlank(params.getBusinessKey())) {
            BookApply bookApply = bookApplyService.getById(params.getBusinessKey().split(":")[1]);
            bookApply.setStatus(0);
            bookApplyService.updateById(bookApply);
            List<ApplyBook> applyBooks = applyBookService.findBooksByApplyId(bookApply.getId());
            applyBooks.forEach(applyBook -> {
                applyBook.setBorrowDateTime(null);
                applyBook.setStatus(0);
            });
            applyBookService.updateBatchById(applyBooks);
            return R.ok(CommonConstants.SUCCESS, "修改状态成功");
        }
        return R.ok(CommonConstants.FAIL, "回退至起草环节回调方法");
    }

    @ApiOperation(value = "流程结束回调方法", notes = "流程结束回调方法")
    @PostMapping(value = "/flowEnd", produces = "application/json")
    public R<Integer> finishEndCallback(@RequestBody FlowCallBackDto params) {
        if (params != null && StrUtil.isNotBlank(params.getBusinessKey())) {
            BookApply bookApply = bookApplyService.getById(params.getBusinessKey().split(":")[1]);
            int status = 2;
            if (ProcessStatusEnum.ZZ.toString().equals(params.getProcessStatus())) {
                status = 99;
            } else {
                List<ApplyBook> applyBooks = applyBookService.findBooksByApplyId(bookApply.getId());
                applyBooks.forEach(applyBook -> {
                    applyBook.setBorrowDateTime(LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DatePattern.NORM_DATETIME_PATTERN));
                    applyBook.setStatus(2);
                });
                applyBookService.updateBatchById(applyBooks);

                List<Book> books = bookService.listByIds(applyBooks.stream().map(ApplyBook::getBookId).collect(Collectors.toSet()));
                books.forEach(book -> book.setStatus(1));
                bookService.updateBatchById(books);
            }

            bookApply.setStatus(status);
            bookApplyService.updateById(bookApply);
            return R.ok(CommonConstants.SUCCESS, "修改状态成功");
        }
        return R.failed(CommonConstants.FAIL, "未找到对应的业务数据");
    }
}
